/*
 * @(#)ReflectUtil.java 1.0 2008/12/07
 */
package stardust.core.java.reflect;


import java.lang.reflect.Method;


/**
 * <code>ReflectUtil</code> 类是为反射提供命名规范和类型匹配的工具。
 * <p/>
 * @see MethodReflect
 * @see FieldReflect
 * @version 1.0, 2008/12/07
 * @author ChenChang
 */
public class ReflectUtil
{

  public static final String SETTER = "set";

  public static final String GETTER = "get";

  /**
   * <code>ReflectUtil</code> 类不允许被实例化，它并没有被实例化的必要。
   */
  private ReflectUtil()
  {
  }

  /**
   * 这个方法将一个字符串首字母大写，然后返回转换为属性对应的 Getter 方法名称，只支持帕斯卡命名法的转换。
   * <p/>
   * @param property
   * 一个基于帕斯卡命名法的字符串。
   * <p/>
   * @return 返回转换为属性对应的 Getter 方法名称。
   * <p/>
   * @see #toSetter(String)
   */
  public static String toGetter(String property)
  {
    return GETTER + Character.toUpperCase(property.charAt(0)) + property.substring(1);
  }

  /**
   * 这个方法将一个字符串首字母大写，然后返回转换为属性对应的 Setter 方法名称，只支持帕斯卡命名法的转换。
   * <p/>
   * @param property
   * 一个基于帕斯卡命名法的字符串。
   * <p/>
   * @return 返回转换为属性对应的 Setter 方法名称。
   * <p/>
   * @see #toGetter(String)
   */
  public static String toSetter(String property)
  {
    return SETTER + Character.toUpperCase(property.charAt(0)) + property.substring(1);
  }

  /**
   * 将属性名称前导字符串 Getter/Setter 消除，然后将首字母转换为小写，只支持帕斯卡命名法的转换。
   * <p/>
   * @param property
   * 属性的名称，可以是一个带有 Setter/Getter 的字符串。
   * <p/>
   * @return 转换为标准属性名称后的 {@link String} 对象。
   */
  public static String trimSetterOrGetter(String property)
  {
    if (property.startsWith(GETTER) && property.length() != GETTER.length() && Character.isUpperCase(property.charAt(GETTER.length())))
    {
      property = property.substring(GETTER.length());
    }
    else if (property.startsWith(SETTER) && property.length() != SETTER.length() && Character.isUpperCase(property.charAt(SETTER.length())))
    {
      property = property.substring(GETTER.length());
    }

    return Character.toLowerCase(property.charAt(0)) + property.substring(1);
  }

  /**
   * 将class类文件路径转换为全限定类名。
   * <p/>
   * @param classFile
   * class文件路径，是一个相对路径的字符串。
   * <p/>
   * @return 转换为全限定类名称后的 {@link String} 对象。
   */
  public static String getClassName(String classFile)
  {
    int offset;

    classFile = classFile.replace('\\', '/');
    classFile = classFile.startsWith("/") ? classFile.substring(1) : classFile;

    offset = classFile.lastIndexOf('.');
    if (offset != -1)
    {
      classFile = classFile.substring(0, offset);
    }

    return classFile.replace('/', '.');
  }

  /**
   * <code>getMethod</code> 方法从参数提供的类和方法名称以及参数中查询一个方法，并返回第一个匹配的方法。<br />
   * 如果参数类型不同，但是方法的实参可以转换为对应的方法形参也匹配查询规则。
   * <p/>
   * @param classType
   * 一个要查询的 {@link Class} 类型的对象。
   * @param method
   * 指定要查询的方法，它是 {@link String} 类型。
   * @param parameterClass
   * 期望的方法参数类型数组。
   * <p/>
   * @return 如果找到匹配的方法则返回该方法的引用实例，否则返回 <tt>null</tt> 值。
   */
  public static Method getMethod(Class classType, String method, Class... parameterClass)
  {
    Method[] methods;
    Class[] methodParameterClass;

    try
    {
      return classType.getMethod(method, parameterClass);
    }
    catch(NoSuchMethodException ex)
    {
    }
    catch(SecurityException ex)
    {
    }

    methods = classType.getMethods();

i:  for (int i = 0; i < methods.length; i++)
    {
      if (methods[i].getName().equals(method))
      {
        methodParameterClass = methods[i].getParameterTypes();

        if (methodParameterClass.length == parameterClass.length)
        {
          for (int j = 0; j < methodParameterClass.length; j++)
          {
            if (!TypeUtils.testCastToType(parameterClass[j] == null ? methodParameterClass[j] : parameterClass[j], methodParameterClass[j]))
            {
              continue i;
            }
          }

          return methods[i];
        }
      }
    }

    return null;
  }

}
